home *** CD-ROM | disk | FTP | other *** search
- /* dither2x2.c
- * AUTHOR: Cy Booker, cy@cheepnis.demon.co.uk
- * LICENSE: FreeWare, Copyright (c) 1995 Cy Booker
- */
-
- #include "internal.h"
-
- #include <assert.h>
- #include <string.h> /* memset() */
-
- #include "OS:macros.h"
- #include "OS:hourglass.h"
-
-
- #include <stdio.h>
-
- /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- */
-
- static void calculate_dither2x2(
- const process_gif *p,
- byte dither[2][2],
- os_colour colour);
-
-
-
- /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- */
-
- extern bool process_gif_8bpp_dither2x2(
- const process_gif *p) {
- bits *rove;
- bits dest;
- int width, height;
- int x, y;
- const os_colour *palette;
- int line_length;
- bits t;
- int index;
- byte dither[256][2][2];
-
- assert(p);
- assert(p->pixel_width > 0);
- assert(p->pixel_height > 0);
- assert(p->in_palette.colours);
- assert(p->out_palette.colours);
- assert((p->line_length & 3) == 0);
- assert(p->fn);
-
- /*
- * pre-calculate dither table
- * to save a function call in middle loop
- * thus the compiler has more registers to play with
- */
- palette = p->in_palette.colours;
- for (index= p->in_palette.ncolours; (index > 0);) {
- index--;
- calculate_dither2x2(p, dither[index], palette[index]);
- }
-
- /*
- * note we pre-load values from the process_gif structure
- * because it considerably helps the compiler produce better code
- */
- rove = (bits *)p->buffer;
- height = p->pixel_height;
- width = ((p->pixel_width + 3) & ~3) >> 2;
- line_length = p->line_length >> 2;
-
- for (y= height; (y > 0); y--) {
- if ((y & 7) == 0) {
- xhourglass_percentage((y * 100) / height);
- }
- for (x= width - 1; (x >= 0); x--) {
- /*
- * reading/writing one 32-bit word is much faster than four bytes
- */
- t = rove[x];
- dest = dither[(t << (3*8)) >> 24][y & 1][0] << (0*8);
- dest |= dither[(t << (1*8)) >> 24][y & 1][0] << (2*8);
- dest |= dither[(t << (2*8)) >> 24][y & 1][1] << (1*8);
- dest |= dither[(t << (0*8)) >> 24][y & 1][1] << (3*8);
- rove[x] = dest;
- }
- rove += line_length;
- }
- return FALSE;
- }
-
-
-
- /* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
- */
-
- static void calculate_dither2x2(
- const process_gif *p,
- byte dither[2][2],
- os_colour colour) {
- int target_red, target_grn, target_blu;
- int red, grn, blu;
- rgbtupleout err;
- register int err_red, err_grn, err_blu;
- int t;
-
-
- err.palette = p->out_palette; /* structure copy */
- /*
- * we now use ``colourtrns'' dithering algorithm, where X is the
- * destination colour, and all values are (r, g, b) tuples
- * topleft <-- X
- * bottomright <-- X - (topleft - X)
- * topright <-- X - (((topleft - X) + (bottomright - X)) / 2)
- * bottomleft <-- X - (((topleft - X) + (bottomright - X) + (topright - X)) / 3)
- *
- * personally, I don't see why the need for divisions, as surely we are using:
- * "OK we missed X by N, therefore compensate by choosing X - N"
- *
- * humph, it works, anyway
- */
-
- target_red = (colour >> (1 * 8)) & 0xff; target_red |= target_red << 8;
- target_grn = (colour >> (2 * 8)) & 0xff; target_grn |= target_grn << 8;
- target_blu = (colour >> (3 * 8)) & 0xff; target_blu |= target_blu << 8;
- dither[0][0] = (*p->fn)(&err, target_red, target_grn, target_blu);
- err_red = err.colour.red; err_grn = err.colour.grn; err_blu = err.colour.blu;
- /*
- * the err.colour is the error in representing the input red, grn, blu
- * on later iterations we need to add in the error of the output colour from the target colour
- */
-
- red = target_red + err_red;
- grn = target_grn + err_grn;
- blu = target_blu + err_blu;
- dither[1][1] = t = (*p->fn)(&err, red, grn, blu);
- red = err.colour.red; grn = err.colour.grn; blu = err.colour.blu;
- err_red += red; err_grn += grn; err_blu += blu; /* local error */
- red = p->out_palette.colours[t].red; grn = p->out_palette.colours[t].grn; blu = p->out_palette.colours[t].blu;
- err_red += target_red - red; err_grn += target_grn - grn; err_blu += target_blu - blu;
-
- red = target_red + (err_red / 2);
- grn = target_grn + (err_grn / 2);
- blu = target_blu + (err_blu / 2);
- dither[0][1] = t = (*p->fn)(&err, red, grn, blu);
- red = err.colour.red; grn = err.colour.grn; blu = err.colour.blu;
- err_red += red; err_grn += grn; err_blu += blu; /* local error */
- red = p->out_palette.colours[t].red; grn = p->out_palette.colours[t].grn; blu = p->out_palette.colours[t].blu;
- err_red += target_red - red; err_grn += target_grn - grn; err_blu += target_blu - blu;
-
- red = target_red + (err_red / 3);
- grn = target_grn + (err_grn / 3);
- blu = target_blu + (err_blu / 3);
- dither[1][0] = (*p->fn)(&err, red, grn, blu);
- }
-
-
-